From e580c29f07f42fb171264a97389a18a2a7cdb3cd Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 15 May 2014 15:03:18 +0200 Subject: [PATCH] entry: Use gestures to handle pointer/touch events Similarly to GtkTextView, a GtkGestureMultiPress gesture handles button/touch presses to initiate one selection mode or other, and a GtkGestureDrag is used to handle text selection and DnD checks. The code from button press/release, motion, and grab_notify handlers has been shuffled into the actions triggered by those gestures. --- gtk/gtkentry.c | 671 +++++++++++++++++++++++++------------------------ 1 file changed, 343 insertions(+), 328 deletions(-) diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 4f97458e4a..27368cc5c6 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -143,8 +143,6 @@ struct _GtkEntryPrivate GtkIMContext *im_context; GtkWidget *popup_menu; - GdkDevice *device; - GdkWindow *text_area; PangoLayout *cached_layout; @@ -167,6 +165,9 @@ struct _GtkEntryPrivate GtkWidget *magnifier_popover; GtkWidget *magnifier; + GtkGesture *drag_gesture; + GtkGesture *multipress_gesture; + gfloat xalign; gint ascent; /* font ascent in pango units */ @@ -185,7 +186,6 @@ struct _GtkEntryPrivate gunichar invisible_char; - guint button; guint blink_time; /* time in msec the cursor has blinked since last user event */ guint blink_timeout; guint recompute_idle; @@ -385,16 +385,12 @@ static void gtk_entry_draw_progress (GtkWidget *widget, cairo_t *cr); static gint gtk_entry_draw (GtkWidget *widget, cairo_t *cr); -static gint gtk_entry_button_press (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_entry_button_release (GtkWidget *widget, - GdkEventButton *event); +static gboolean gtk_entry_event (GtkWidget *widget, + GdkEvent *event); static gint gtk_entry_enter_notify (GtkWidget *widget, GdkEventCrossing *event); static gint gtk_entry_leave_notify (GtkWidget *widget, GdkEventCrossing *event); -static gint gtk_entry_motion_notify (GtkWidget *widget, - GdkEventMotion *event); static gint gtk_entry_key_press (GtkWidget *widget, GdkEventKey *event); static gint gtk_entry_key_release (GtkWidget *widget, @@ -524,6 +520,21 @@ static gboolean gtk_entry_delete_surrounding_cb (GtkIMContext *context, gint n_chars, GtkEntry *entry); +/* Event controller callbacks */ +static void gtk_entry_multipress_gesture_pressed (GtkGestureMultiPress *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkEntry *entry); +static void gtk_entry_drag_gesture_update (GtkGestureDrag *gesture, + gdouble offset_x, + gdouble offset_y, + GtkEntry *entry); +static void gtk_entry_drag_gesture_end (GtkGestureDrag *gesture, + gdouble offset_x, + gdouble offset_y, + GtkEntry *entry); + /* Internal routines */ static void gtk_entry_enter_text (GtkEntry *entry, @@ -566,11 +577,9 @@ static void gtk_entry_paste (GtkEntry *entry, GdkAtom selection); static void gtk_entry_update_primary_selection (GtkEntry *entry); static void gtk_entry_do_popup (GtkEntry *entry, - GdkEventButton *event); + const GdkEvent *event); static gboolean gtk_entry_mnemonic_activate (GtkWidget *widget, gboolean group_cycling); -static void gtk_entry_grab_notify (GtkWidget *widget, - gboolean was_grabbed); static void gtk_entry_check_cursor_blink (GtkEntry *entry); static void gtk_entry_pend_cursor_blink (GtkEntry *entry); static void gtk_entry_reset_blink_time (GtkEntry *entry); @@ -696,9 +705,7 @@ gtk_entry_class_init (GtkEntryClass *class) widget_class->draw = gtk_entry_draw; widget_class->enter_notify_event = gtk_entry_enter_notify; widget_class->leave_notify_event = gtk_entry_leave_notify; - widget_class->button_press_event = gtk_entry_button_press; - widget_class->button_release_event = gtk_entry_button_release; - widget_class->motion_notify_event = gtk_entry_motion_notify; + widget_class->event = gtk_entry_event; widget_class->key_press_event = gtk_entry_key_press; widget_class->key_release_event = gtk_entry_key_release; widget_class->focus_in_event = gtk_entry_focus_in; @@ -712,7 +719,6 @@ gtk_entry_class_init (GtkEntryClass *class) widget_class->state_flags_changed = gtk_entry_state_flags_changed; widget_class->screen_changed = gtk_entry_screen_changed; widget_class->mnemonic_activate = gtk_entry_mnemonic_activate; - widget_class->grab_notify = gtk_entry_grab_notify; widget_class->drag_drop = gtk_entry_drag_drop; widget_class->drag_motion = gtk_entry_drag_motion; @@ -2687,6 +2693,22 @@ gtk_entry_init (GtkEntry *entry) gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY); gtk_entry_update_cached_style_values (entry); + + priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (entry)); + g_signal_connect (priv->drag_gesture, "drag-update", + G_CALLBACK (gtk_entry_drag_gesture_update), entry); + g_signal_connect (priv->drag_gesture, "drag-end", + G_CALLBACK (gtk_entry_drag_gesture_end), entry); + gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->drag_gesture), FALSE); + gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->drag_gesture), TRUE); + gtk_gesture_attach (priv->drag_gesture, GTK_PHASE_TARGET); + + priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (entry)); + g_signal_connect (priv->multipress_gesture, "pressed", + G_CALLBACK (gtk_entry_multipress_gesture_pressed), entry); + gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->multipress_gesture), FALSE); + gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->multipress_gesture), TRUE); + gtk_gesture_attach (priv->multipress_gesture, GTK_PHASE_TARGET); } static void @@ -4178,289 +4200,292 @@ gtk_entry_update_handles (GtkEntry *entry, cursor, 0, height); } -static gint -gtk_entry_button_press (GtkWidget *widget, - GdkEventButton *event) +static gboolean +gtk_entry_event (GtkWidget *widget, + GdkEvent *event) { - GtkEntry *entry = GTK_ENTRY (widget); - GtkEditable *editable = GTK_EDITABLE (widget); - GtkEntryPrivate *priv = entry->priv; + GtkEntryPrivate *priv = GTK_ENTRY (widget)->priv; EntryIconInfo *icon_info = NULL; - gint tmp_pos; - gint sel_start, sel_end; gint i; - gtk_entry_selection_bubble_popup_unset (entry); - - for (i = 0; i < MAX_ICONS; i++) + if (event->type == GDK_MOTION_NOTIFY && + priv->mouse_cursor_obscured && + event->any.window == priv->text_area) { - icon_info = priv->icons[i]; + GdkCursor *cursor; - if (!icon_info || icon_info->insensitive) - continue; + cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM); + gdk_window_set_cursor (priv->text_area, cursor); + g_object_unref (cursor); + priv->mouse_cursor_obscured = FALSE; + return GDK_EVENT_PROPAGATE; + } - if (event->window == icon_info->window) + for (i = 0; i < MAX_ICONS; i++) + { + if (priv->icons[i] && + priv->icons[i]->window == event->any.window) { - if (should_prelight (entry, i)) - { - icon_info->prelight = FALSE; - gtk_widget_queue_draw (widget); - } + icon_info = priv->icons[i]; + break; + } + } - priv->start_x = event->x; - priv->start_y = event->y; - icon_info->pressed = TRUE; + if (!icon_info) + return GDK_EVENT_PROPAGATE; - if (!icon_info->nonactivatable) - g_signal_emit (entry, signals[ICON_PRESS], 0, i, event); + if (icon_info->insensitive) + return GDK_EVENT_STOP; - return TRUE; + switch (event->type) + { + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + if (should_prelight (GTK_ENTRY (widget), i)) + { + icon_info->prelight = FALSE; + gtk_widget_queue_draw (widget); } - } - if (event->window != priv->text_area || - (priv->button && event->button != priv->button)) - return FALSE; + priv->start_x = event->button.x; + priv->start_y = event->button.y; + icon_info->pressed = TRUE; - gtk_entry_reset_blink_time (entry); + if (!icon_info->nonactivatable) + g_signal_emit (widget, signals[ICON_PRESS], 0, i, event); - priv->button = event->button; - priv->device = gdk_event_get_device ((GdkEvent *) event); + break; + case GDK_MOTION_NOTIFY: + if (icon_info->pressed && + icon_info->target_list != NULL && + gtk_drag_check_threshold (widget, + priv->start_x, + priv->start_y, + event->motion.x, + event->motion.y)) + { + icon_info->in_drag = TRUE; + icon_info->pressed = FALSE; + gtk_drag_begin_with_coordinates (widget, + icon_info->target_list, + icon_info->actions, + 1, + event, + priv->start_x, + priv->start_y); + } - if (!gtk_widget_has_focus (widget)) - { - priv->in_click = TRUE; - gtk_widget_grab_focus (widget); - priv->in_click = FALSE; - } + break; + case GDK_BUTTON_RELEASE: + icon_info->pressed = FALSE; - tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset); + if (should_prelight (GTK_ENTRY (widget), i) && + event->button.x >= 0 && event->button.y >= 0 && + event->button.x < gdk_window_get_width (icon_info->window) && + event->button.y < gdk_window_get_height (icon_info->window)) + { + icon_info->prelight = TRUE; + gtk_widget_queue_draw (widget); + } - if (gdk_event_triggers_context_menu ((GdkEvent *) event)) - { - gtk_entry_do_popup (entry, event); - priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */ - priv->device = NULL; + if (!icon_info->nonactivatable) + g_signal_emit (widget, signals[ICON_RELEASE], 0, i, event); - return TRUE; + break; + default: + return GDK_EVENT_PROPAGATE; } - else if (event->button == GDK_BUTTON_PRIMARY) - { - gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end); - gboolean is_touchscreen; - GdkDevice *source; - source = gdk_event_get_source_device ((GdkEvent *) event); - is_touchscreen = test_touchscreen || - gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN; + return GDK_EVENT_STOP; +} - if (is_touchscreen) - gtk_entry_ensure_text_handles (entry); +static void +gesture_get_current_point (GtkGestureSingle *gesture, + GtkEntry *entry, + gint *x, + gint *y) +{ + GtkAllocation primary, secondary; + gint frame_x, frame_y, tx, ty; + GdkEventSequence *sequence; + gdouble px, py; - priv->select_words = FALSE; - priv->select_lines = FALSE; + sequence = gtk_gesture_single_get_current_sequence (gesture); + gtk_gesture_get_point (GTK_GESTURE (gesture), sequence, &px, &py); + get_text_area_size (entry, &tx, &ty, NULL, NULL); + get_icon_allocations (entry, &primary, &secondary); + get_frame_size (entry, FALSE, &frame_x, &frame_y, NULL, NULL); - if (event->state & - gtk_widget_get_modifier_mask (widget, - GDK_MODIFIER_INTENT_EXTEND_SELECTION)) - { - gtk_entry_reset_im_context (entry); + if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + tx += secondary.width; + else + tx += primary.width; - if (!have_selection) /* select from the current position to the clicked position */ - sel_start = sel_end = priv->current_pos; + tx += frame_x; + ty += frame_y; - if (tmp_pos > sel_start && tmp_pos < sel_end) - { - /* Truncate current selection, but keep it as big as possible */ - if (tmp_pos - sel_start > sel_end - tmp_pos) - gtk_entry_set_positions (entry, sel_start, tmp_pos); - else - gtk_entry_set_positions (entry, tmp_pos, sel_end); - } - else - { - gboolean extend_to_left; - gint start, end; + if (x) + *x = px - tx; + if (y) + *y = py - ty; +} - /* Figure out what click selects and extend current selection */ - switch (event->type) - { - case GDK_BUTTON_PRESS: - gtk_entry_set_positions (entry, tmp_pos, tmp_pos); - break; - - case GDK_2BUTTON_PRESS: - priv->select_words = TRUE; - gtk_entry_select_word (entry); - break; - - case GDK_3BUTTON_PRESS: - priv->select_lines = TRUE; - gtk_entry_select_line (entry); - break; - - default: - break; - } +static void +gtk_entry_multipress_gesture_pressed (GtkGestureMultiPress *gesture, + gint n_press, + gdouble widget_x, + gdouble widget_y, + GtkEntry *entry) +{ + GtkEditable *editable = GTK_EDITABLE (entry); + GtkWidget *widget = GTK_WIDGET (entry); + GtkEntryPrivate *priv = entry->priv; + GdkEventSequence *current; + const GdkEvent *event; + gint x, y, sel_start, sel_end; + guint button; + gint tmp_pos; - start = MIN (priv->current_pos, priv->selection_bound); - start = MIN (sel_start, start); - - end = MAX (priv->current_pos, priv->selection_bound); - end = MAX (sel_end, end); + gtk_entry_selection_bubble_popup_unset (entry); - if (tmp_pos == sel_start || tmp_pos == sel_end) - extend_to_left = (tmp_pos == start); - else - extend_to_left = (end == sel_end); - - if (extend_to_left) - gtk_entry_set_positions (entry, start, end); - else - gtk_entry_set_positions (entry, end, start); - } - } - else /* no shift key */ - switch (event->type) - { - case GDK_BUTTON_PRESS: - if (in_selection (entry, event->x + priv->scroll_offset)) - { - /* Click inside the selection - we'll either start a drag, or - * clear the selection - */ - priv->in_drag = TRUE; - priv->drag_start_x = event->x + priv->scroll_offset; - priv->drag_start_y = event->y; - } - else - { - gtk_editable_set_position (editable, tmp_pos); - if (is_touchscreen) - gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_NONE); - } - break; - - case GDK_2BUTTON_PRESS: - /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before - * receiving a GDK_2BUTTON_PRESS so we need to reset - * priv->in_drag which may have been set above - */ - priv->in_drag = FALSE; - priv->select_words = TRUE; - gtk_entry_select_word (entry); + button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)); + current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)); + event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), current); - if (is_touchscreen) - gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION); - break; - - case GDK_3BUTTON_PRESS: - /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before - * receiving a GDK_3BUTTON_PRESS so we need to reset - * priv->in_drag which may have been set above - */ - priv->in_drag = FALSE; - priv->select_lines = TRUE; - gtk_entry_select_line (entry); - if (is_touchscreen) - gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION); - break; + gtk_gesture_set_sequence_state (GTK_GESTURE (gesture), current, + GTK_EVENT_SEQUENCE_CLAIMED); + gesture_get_current_point (GTK_GESTURE_SINGLE (gesture), entry, &x, &y); + gtk_entry_reset_blink_time (entry); - default: - break; - } + if (!gtk_widget_has_focus (widget)) + { + priv->in_click = TRUE; + gtk_widget_grab_focus (widget); + priv->in_click = FALSE; + } - return TRUE; + tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset); + + if (gdk_event_triggers_context_menu ((GdkEvent *) event)) + { + gtk_entry_do_popup (entry, event); } - else if (event->type == GDK_BUTTON_PRESS && - event->button == GDK_BUTTON_MIDDLE && + else if (n_press == 1 && button == GDK_BUTTON_MIDDLE && get_middle_click_paste (entry)) { if (priv->editable) { priv->insert_pos = tmp_pos; gtk_entry_paste (entry, GDK_SELECTION_PRIMARY); - return TRUE; } else { gtk_widget_error_bell (widget); } } + else if (button == GDK_BUTTON_PRIMARY) + { + gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end); + GtkTextHandleMode mode = GTK_TEXT_HANDLE_MODE_NONE; + gboolean is_touchscreen, extend_selection; + GdkDevice *source; - return FALSE; -} + source = gdk_event_get_source_device (event); + is_touchscreen = test_touchscreen || + gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN; -static gint -gtk_entry_button_release (GtkWidget *widget, - GdkEventButton *event) -{ - GtkEntry *entry = GTK_ENTRY (widget); - GtkEntryPrivate *priv = entry->priv; - EntryIconInfo *icon_info = NULL; - gboolean is_touchscreen; - GdkDevice *source; - gint i; + if (is_touchscreen) + gtk_entry_ensure_text_handles (entry); - for (i = 0; i < MAX_ICONS; i++) - { - icon_info = priv->icons[i]; + priv->in_drag = FALSE; + priv->select_words = FALSE; + priv->select_lines = FALSE; - if (!icon_info || icon_info->insensitive) - continue; + extend_selection = + (event->button.state & + gtk_widget_get_modifier_mask (widget, + GDK_MODIFIER_INTENT_EXTEND_SELECTION)); - if (event->window == icon_info->window) + switch (n_press) { - icon_info->pressed = FALSE; - - if (should_prelight (entry, i) && - event->x >= 0 && event->y >= 0 && - event->x < gdk_window_get_width (icon_info->window) && - event->y < gdk_window_get_height (icon_info->window)) + case 1: + if (in_selection (entry, x + priv->scroll_offset)) { - icon_info->prelight = TRUE; - gtk_widget_queue_draw (widget); + /* Click inside the selection - we'll either start a drag, or + * clear the selection + */ + priv->in_drag = TRUE; + priv->drag_start_x = x + priv->scroll_offset; + priv->drag_start_y = y; } + else if (!extend_selection) + { + gtk_editable_set_position (editable, tmp_pos); + } + else + { + gtk_entry_reset_im_context (entry); + + if (!have_selection) /* select from the current position to the clicked position */ + sel_start = sel_end = priv->current_pos; - if (!icon_info->nonactivatable) - g_signal_emit (entry, signals[ICON_RELEASE], 0, i, event); + if (tmp_pos > sel_start && tmp_pos < sel_end) + { + /* Truncate current selection, but keep it as big as possible */ + if (tmp_pos - sel_start > sel_end - tmp_pos) + gtk_entry_set_positions (entry, sel_start, tmp_pos); + else + gtk_entry_set_positions (entry, tmp_pos, sel_end); + } + } - return TRUE; + break; + case 2: + priv->select_words = TRUE; + gtk_entry_select_word (entry); + mode = GTK_TEXT_HANDLE_MODE_SELECTION; + break; + case 3: + priv->select_lines = TRUE; + gtk_entry_select_line (entry); + mode = GTK_TEXT_HANDLE_MODE_SELECTION; + break; + default: + break; } - } - if (event->window != priv->text_area || priv->button != event->button) - return FALSE; + if (extend_selection) + { + gboolean extend_to_left; + gint start, end; - source = gdk_event_get_source_device ((GdkEvent *) event); - is_touchscreen = (test_touchscreen || - gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN); + start = MIN (priv->current_pos, priv->selection_bound); + start = MIN (sel_start, start); - if (priv->in_drag) - { - gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x); + end = MAX (priv->current_pos, priv->selection_bound); + end = MAX (sel_end, end); - gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos); + if (tmp_pos == sel_start || tmp_pos == sel_end) + extend_to_left = (tmp_pos == start); + else + extend_to_left = (end == sel_end); - if (is_touchscreen) - gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR); + if (extend_to_left) + gtk_entry_set_positions (entry, start, end); + else + gtk_entry_set_positions (entry, end, start); + } - priv->in_drag = 0; - } - else if (is_touchscreen) - { - gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR); - gtk_entry_selection_bubble_popup_set (entry); - if (priv->magnifier_popover) - gtk_widget_hide (priv->magnifier_popover); - } + gtk_gesture_set_state (priv->drag_gesture, + GTK_EVENT_SEQUENCE_CLAIMED); - priv->button = 0; - priv->device = NULL; + if (is_touchscreen) + gtk_entry_update_handles (entry, mode); + } - gtk_entry_update_primary_selection (entry); - - return TRUE; + if (n_press >= 3) + gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture)); } static gchar * @@ -4508,47 +4533,21 @@ gtk_entry_show_magnifier (GtkEntry *entry, gtk_widget_show (priv->magnifier_popover); } -static gint -gtk_entry_motion_notify (GtkWidget *widget, - GdkEventMotion *event) +static void +gtk_entry_drag_gesture_update (GtkGestureDrag *gesture, + gdouble offset_x, + gdouble offset_y, + GtkEntry *entry) { - GtkEntry *entry = GTK_ENTRY (widget); + GtkWidget *widget = GTK_WIDGET (entry); GtkEntryPrivate *priv = entry->priv; - EntryIconInfo *icon_info = NULL; - gint tmp_pos; - gint i; - - for (i = 0; i < MAX_ICONS; i++) - { - icon_info = priv->icons[i]; - - if (!icon_info || icon_info->insensitive) - continue; - - if (event->window == icon_info->window) - { - if (icon_info->pressed && - icon_info->target_list != NULL && - gtk_drag_check_threshold (widget, - priv->start_x, - priv->start_y, - event->x, - event->y)) - { - icon_info->in_drag = TRUE; - icon_info->pressed = FALSE; - gtk_drag_begin_with_coordinates (widget, - icon_info->target_list, - icon_info->actions, - 1, - (GdkEvent*)event, - priv->start_x, - priv->start_y); - } + GdkEventSequence *sequence; + const GdkEvent *event; + gint x, y; - return TRUE; - } - } + gesture_get_current_point (GTK_GESTURE_SINGLE (gesture), entry, &x, &y); + sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)); + event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence); if (priv->mouse_cursor_obscured) { @@ -4560,20 +4559,15 @@ gtk_entry_motion_notify (GtkWidget *widget, priv->mouse_cursor_obscured = FALSE; } - if (event->window != priv->text_area || priv->button != GDK_BUTTON_PRIMARY) - return FALSE; - if (priv->select_lines) - return TRUE; - - gdk_event_request_motions (event); + return; if (priv->in_drag) { if (gtk_entry_get_display_mode (entry) == DISPLAY_NORMAL && gtk_drag_check_threshold (widget, priv->drag_start_x, priv->drag_start_y, - event->x + priv->scroll_offset, event->y)) + x + priv->scroll_offset, y)) { gint *ranges; gint n_ranges; @@ -4582,6 +4576,7 @@ gtk_entry_motion_notify (GtkWidget *widget, guint actions = priv->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY; gchar *text = NULL; cairo_surface_t *surface; + guint button; gtk_target_list_add_text_targets (target_list, 0); @@ -4593,8 +4588,9 @@ gtk_entry_motion_notify (GtkWidget *widget, -(priv->drag_start_x - ranges[0]), -(priv->drag_start_y)); + button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)); context = gtk_drag_begin_with_coordinates (widget, target_list, actions, - priv->button, (GdkEvent *)event, + button, (GdkEvent*) event, priv->drag_start_x + ranges[0], priv->drag_start_y); g_free (ranges); @@ -4603,14 +4599,12 @@ gtk_entry_motion_notify (GtkWidget *widget, gtk_drag_set_icon_surface (context, surface); else gtk_drag_set_icon_default (context); - + if (surface) cairo_surface_destroy (surface); g_free (text); priv->in_drag = FALSE; - priv->button = 0; - priv->device = NULL; gtk_target_list_unref (target_list); } @@ -4620,17 +4614,18 @@ gtk_entry_motion_notify (GtkWidget *widget, GdkInputSource input_source; GdkDevice *source; guint length; + gint tmp_pos; length = gtk_entry_buffer_get_length (get_buffer (entry)); - if (event->y < 0) + if (y < 0) tmp_pos = 0; - else if (event->y >= gdk_window_get_height (priv->text_area)) + else if (y >= gdk_window_get_height (priv->text_area)) tmp_pos = length; else - tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset); + tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset); - source = gdk_event_get_source_device ((GdkEvent *) event); + source = gdk_event_get_source_device (event); input_source = gdk_device_get_source (source); if (priv->select_words) @@ -4638,32 +4633,32 @@ gtk_entry_motion_notify (GtkWidget *widget, gint min, max; gint old_min, old_max; gint pos, bound; - + min = gtk_entry_move_backward_word (entry, tmp_pos, TRUE); max = gtk_entry_move_forward_word (entry, tmp_pos, TRUE); pos = priv->current_pos; bound = priv->selection_bound; - old_min = MIN(priv->current_pos, priv->selection_bound); - old_max = MAX(priv->current_pos, priv->selection_bound); - + old_min = MIN (priv->current_pos, priv->selection_bound); + old_max = MAX (priv->current_pos, priv->selection_bound); + if (min < old_min) { pos = min; bound = old_max; } - else if (old_max < max) + else if (old_max < max) { pos = max; bound = old_min; } - else if (pos == old_min) + else if (pos == old_min) { if (priv->current_pos != min) pos = max; } - else + else { if (priv->current_pos != max) pos = min; @@ -4677,22 +4672,59 @@ gtk_entry_motion_notify (GtkWidget *widget, /* Update touch handles' position */ if (test_touchscreen || input_source == GDK_SOURCE_TOUCHSCREEN) { - gint x, y; - gtk_entry_ensure_text_handles (entry); gtk_entry_update_handles (entry, (priv->current_pos == priv->selection_bound) ? GTK_TEXT_HANDLE_MODE_CURSOR : GTK_TEXT_HANDLE_MODE_SELECTION); - - gtk_entry_get_text_area_size (entry, &x, &y, NULL, NULL); - x += event->x; - y += event->y; gtk_entry_show_magnifier (entry, x, y); } } +} - return TRUE; +static void +gtk_entry_drag_gesture_end (GtkGestureDrag *gesture, + gdouble offset_x, + gdouble offset_y, + GtkEntry *entry) +{ + GtkEntryPrivate *priv = entry->priv; + gboolean in_drag, is_touchscreen; + GdkEventSequence *sequence; + const GdkEvent *event; + GdkDevice *source; + + sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)); + in_drag = priv->in_drag; + priv->in_drag = FALSE; + + if (priv->magnifier_popover) + gtk_widget_hide (priv->magnifier_popover); + + /* Check whether the drag was cancelled rather than finished */ + if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence)) + return; + + event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence); + source = gdk_event_get_source_device (event); + is_touchscreen = (test_touchscreen || + gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN); + + if (in_drag) + { + gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x); + + gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos); + + if (is_touchscreen) + gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR); + } + else if (is_touchscreen) + { + gtk_entry_selection_bubble_popup_set (entry); + } + + gtk_entry_update_primary_selection (entry); } static void @@ -7147,8 +7179,11 @@ paste_received (GtkClipboard *clipboard, GtkEntry *entry = GTK_ENTRY (data); GtkEditable *editable = GTK_EDITABLE (entry); GtkEntryPrivate *priv = entry->priv; + guint button; - if (priv->button == GDK_BUTTON_MIDDLE) + button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (priv->multipress_gesture)); + + if (button == GDK_BUTTON_MIDDLE) { gint pos, start, end; pos = priv->insert_pos; @@ -9314,26 +9349,6 @@ gtk_entry_mnemonic_activate (GtkWidget *widget, return TRUE; } -static void -gtk_entry_grab_notify (GtkWidget *widget, - gboolean was_grabbed) -{ - GtkEntryPrivate *priv; - - priv = GTK_ENTRY (widget)->priv; - - if (priv->device && - gtk_widget_device_is_shadowed (widget, priv->device)) - { - /* Unset button so we don't expect - * a button release anymore - */ - priv->button = 0; - priv->device = NULL; - priv->in_drag = FALSE; - } -} - static void append_action_signal (GtkEntry *entry, GtkWidget *menu, @@ -9415,7 +9430,7 @@ popup_position_func (GtkMenu *menu, typedef struct { GtkEntry *entry; - gint button; + guint button; guint time; GdkDevice *device; } PopupInfo; @@ -9497,7 +9512,7 @@ popup_targets_received (GtkClipboard *clipboard, static void gtk_entry_do_popup (GtkEntry *entry, - GdkEventButton *event) + const GdkEvent *event) { PopupInfo *info = g_slice_new (PopupInfo); @@ -9509,9 +9524,9 @@ gtk_entry_do_popup (GtkEntry *entry, if (event) { - info->button = event->button; - info->time = event->time; - info->device = event->device; + gdk_event_get_button (event, &info->button); + info->time = gdk_event_get_time (event); + info->device = gdk_event_get_device (event); } else { -- 2.30.2